From 01d6e09e590d5537e1d66d2e4e2e68e534b0db43 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C3=98yvind=20Kol=C3=A5s?= Date: Sat, 2 Sep 2017 17:09:20 +0200 Subject: [PATCH] babl: add parametric handling for sRGB style TRCs (icc V4) --- babl/babl-icc.c | 100 ++++++++++++++++++++++++++++--------------- babl/babl-internal.h | 2 + babl/babl-trc.c | 77 +++++++++++++++++++++++++++++---- babl/babl-trc.h | 3 +- 4 files changed, 139 insertions(+), 43 deletions(-) diff --git a/babl/babl-icc.c b/babl/babl-icc.c index 5ae66bc..debbc69 100644 --- a/babl/babl-icc.c +++ b/babl/babl-icc.c @@ -315,22 +315,45 @@ static const Babl *babl_trc_from_icc (ICC *state, int offset, g = icc_read (s15f16, offset + 12 + 2 * 0); return babl_trc_gamma (g); break; - case 3: -#if 0 - float a,b,c,d,e,f; - g = icc_read (s15f16, offset + 12 + 2 * 0); - a = icc_read (s15f16, offset + 12 + 2 * 1); - b = icc_read (s15f16, offset + 12 + 2 * 2); - c = icc_read (s15f16, offset + 12 + 2 * 3); - d = icc_read (s15f16, offset + 12 + 2 * 4); - e = icc_read (s15f16, offset + 12 + 2 * 5); - f = icc_read (s15f16, offset + 12 + 2 * 6); -#endif - return babl_trc ("sRGB"); // XXX: not true... and I suspect the CIE L* curve might be expressed as this, - // formula as well, depending on arguments. + { + float a,b,c,d; + g = icc_read (s15f16, offset + 12 + 2 * 0); + a = icc_read (s15f16, offset + 12 + 2 * 1); + b = icc_read (s15f16, offset + 12 + 2 * 2); + c = icc_read (s15f16, offset + 12 + 2 * 3); + d = icc_read (s15f16, offset + 12 + 2 * 4); + //fprintf (stderr, "%f %f %f %f %f\n", g, a, b, c, d); + if (fabs (g - 2.40) < 0.01 && + fabs (a - 26214) < 0.01 && + fabs (b - 0.947875) < 0.01 && + fabs (c - (-3417)) < 0.01) + return babl_trc ("sRGB"); + else + return babl_trc_formula_srgb (g, a, b, c, d); + } + break; + case 4: + { + float a,b,c,d,e,f; + g = icc_read (s15f16, offset + 12 + 2 * 0); + a = icc_read (s15f16, offset + 12 + 2 * 1); + b = icc_read (s15f16, offset + 12 + 2 * 2); + c = icc_read (s15f16, offset + 12 + 2 * 3); + d = icc_read (s15f16, offset + 12 + 2 * 4); + e = icc_read (s15f16, offset + 12 + 2 * 5); + f = icc_read (s15f16, offset + 12 + 2 * 6); + fprintf (stderr, "%f %f %f %f %f %f %f\n", + g, a, b, c, d, e, f); + { + fprintf (stdout, "unhandled parametric sRGB formula TRC type %i\n", function_type); + *error = "unhandled sRGB formula like TRC"; + return babl_trc_gamma (2.2); + } + } break; default: + *error = "unhandled parametric TRC"; fprintf (stdout, "unhandled parametric TRC type %i\n", function_type); return babl_trc_gamma (2.2); break; @@ -399,14 +422,42 @@ switch (trc->type) icc_write (u32, state->o + 4, 0); icc_write (u32, state->o + 8, 0); break; - case BABL_TRC_GAMMA: + case BABL_TRC_FORMULA_GAMMA: icc_allocate_tag (state, name, 14); icc_write (sign, state->o, "curv"); icc_write (u32, state->o + 4, 0); icc_write (u32, state->o + 8, 1); icc_write (u8f8, state->o + 12, trc->gamma); break; + case BABL_TRC_GAMMA_1_8: + icc_allocate_tag (state, name, 14); + icc_write (sign, state->o, "curv"); + icc_write (u32, state->o + 4, 0); + icc_write (u32, state->o + 8, 1); + icc_write (u8f8, state->o + 12, 1.8); + break; + case BABL_TRC_GAMMA_2_2: + icc_allocate_tag (state, name, 14); + icc_write (sign, state->o, "curv"); + icc_write (u32, state->o + 4, 0); + icc_write (u32, state->o + 8, 1); + icc_write (u8f8, state->o + 12, 2.2); + break; + case BABL_TRC_LUT: + icc_allocate_tag (state, name, 13 + trc->lut_size * 2); + icc_write (sign, state->o, "curv"); + icc_write (u32, state->o + 4, 0); + icc_write (u32, state->o + 8, trc->lut_size); + { + int j; + for (j = 0; j < trc->lut_size; j ++) + icc_write (u16, state->o + 12 + j * 2, (int)(trc->lut[j]*65535.5f)); + } + break; + // this is the case catching things not directly representable in v2 case BABL_TRC_SRGB: + case BABL_TRC_FORMULA_SRGB: +// default: { int lut_size = 512; icc_allocate_tag (state, name, 13 + lut_size * 2); @@ -417,28 +468,9 @@ switch (trc->type) int j; for (j = 0; j < lut_size; j ++) icc_write (u16, state->o + 12 + j * 2, - gamma_2_2_to_linear (j / (lut_size-1.0)) * 65535.5); + babl_trc_to_linear ((void*)trc, j / (lut_size-1.0)) * 65535.5); } } - break; - case BABL_TRC_LUT: - icc_allocate_tag (state, name, 13 + trc->lut_size * 2); - icc_write (sign, state->o, "curv"); - icc_write (u32, state->o + 4, 0); - icc_write (u32, state->o + 8, trc->lut_size); - { - int j; - for (j = 0; j < trc->lut_size; j ++) - icc_write (u16, state->o + 12 + j * 2, (int)(trc->lut[j]*65535.5f)); - } - break; - default: - icc_allocate_tag (state, name, 14); - icc_write (sign, state->o, "curv"); - icc_write (u32, state->o + 4, 0); - icc_write (u32, state->o + 8, 1); - icc_write (u8f8, state->o + 12, trc->gamma); - break; } } diff --git a/babl/babl-internal.h b/babl/babl-internal.h index 440f7e8..c7c87cf 100644 --- a/babl/babl-internal.h +++ b/babl/babl-internal.h @@ -362,5 +362,7 @@ int babl_list_destroy (void *data); const char * babl_conversion_create_name (Babl *source, Babl *destination, int is_reference); void _babl_space_add_universal_rgb (const Babl *space); +const Babl * +babl_trc_formula_srgb (double gamma, double a, double b, double c, double d); #endif diff --git a/babl/babl-trc.c b/babl/babl-trc.c index b9f1c49..4aacdef 100644 --- a/babl/babl-trc.c +++ b/babl/babl-trc.c @@ -343,12 +343,6 @@ static inline float babl_powf (float x, float y) return expf (y * logf (x)); } -static inline float _babl_trc_gamma_to_linear (const Babl *trc_, float value) -{ - BablTRC *trc = (void*)trc_; - return babl_powf (value, trc->gamma); -} - static inline void _babl_trc_gamma_to_linear_buf (const Babl *trc_, const float *in, float *out, int in_gap, int out_gap, int components, int count) { @@ -376,6 +370,48 @@ static inline float _babl_trc_gamma_from_linear (const Babl *trc_, float value) return babl_powf (value, trc->rgamma); } +static inline float _babl_trc_gamma_to_linear (const Babl *trc_, float value) +{ + BablTRC *trc = (void*)trc_; + return babl_powf (value, trc->gamma); +} + +static inline float _babl_trc_formula_srgb_from_linear (const Babl *trc_, float value) +{ + BablTRC *trc = (void*)trc_; + float x= value; + float g = trc->lut[0]; + float a = trc->lut[1]; + float b = trc->lut[2]; + float c = trc->lut[3]; + float d = trc->lut[4]; + if (x > c * d) // XXX: verify that this math is the correct inverse + { + float v = babl_powf (x, 1.0/g); + v = (v-b)/a; + return v; + } + return x / c; +} + +static inline float _babl_trc_formula_srgb_to_linear (const Babl *trc_, float value) +{ + BablTRC *trc = (void*)trc_; + float x= value; + float g = trc->lut[0]; + float a = trc->lut[1]; + float b = trc->lut[2]; + float c = trc->lut[3]; + float d = trc->lut[4]; + + if (x >= d) + { + return babl_powf (a * x + b, g); + } + return c * x; +} + + static inline float _babl_trc_gamma_1_8_to_linear (const Babl *trc_, float x) { if (x >= 0.01f && x < 0.7f) @@ -691,12 +727,22 @@ babl_trc_new (const char *name, trc_db[i].fun_from_linear_buf = _babl_trc_linear_buf; trc_db[i].fun_to_linear_buf = _babl_trc_linear_buf; break; - case BABL_TRC_GAMMA: + case BABL_TRC_FORMULA_GAMMA: trc_db[i].fun_to_linear = _babl_trc_gamma_to_linear; trc_db[i].fun_from_linear = _babl_trc_gamma_from_linear; trc_db[i].fun_to_linear_buf = _babl_trc_gamma_to_linear_buf; trc_db[i].fun_from_linear_buf = _babl_trc_gamma_from_linear_buf; break; + case BABL_TRC_FORMULA_SRGB: + trc_db[i].lut = babl_calloc (sizeof (float), 5); + { + int j; + for (j = 0; j < 5; j++) + trc_db[i].lut[j] = lut[j]; + } + trc_db[i].fun_to_linear = _babl_trc_formula_srgb_to_linear; + trc_db[i].fun_from_linear = _babl_trc_formula_srgb_from_linear; + break; case BABL_TRC_GAMMA_2_2: trc_db[i].fun_to_linear = _babl_trc_gamma_2_2_to_linear; trc_db[i].fun_from_linear = _babl_trc_gamma_2_2_from_linear; @@ -738,6 +784,21 @@ babl_trc_class_for_each (BablEachFunction each_fun, return; } +const Babl * +babl_trc_formula_srgb (double gamma, double a, double b, double c, double d) +{ + char name[32]; + int i; + float params[5]={gamma, a, b, c, d}; + + sprintf (name, "%.6f %.6f %.4f %.4f %.4f", gamma, a, b, c, d); + for (i = 0; name[i]; i++) + if (name[i] == ',') name[i] = '.'; + while (name[strlen(name)-1]=='0') + name[strlen(name)-1]='\0'; + return babl_trc_new (name, BABL_TRC_FORMULA_SRGB, gamma, 0, params); +} + const Babl * babl_trc_gamma (double gamma) { @@ -755,7 +816,7 @@ babl_trc_gamma (double gamma) if (name[i] == ',') name[i] = '.'; while (name[strlen(name)-1]=='0') name[strlen(name)-1]='\0'; - return babl_trc_new (name, BABL_TRC_GAMMA, gamma, 0, NULL); + return babl_trc_new (name, BABL_TRC_FORMULA_GAMMA, gamma, 0, NULL); } void diff --git a/babl/babl-trc.h b/babl/babl-trc.h index 0b7fb70..95020b9 100644 --- a/babl/babl-trc.h +++ b/babl/babl-trc.h @@ -26,10 +26,11 @@ BABL_CLASS_DECLARE (trc); typedef enum {BABL_TRC_LINEAR, - BABL_TRC_GAMMA, + BABL_TRC_FORMULA_GAMMA, BABL_TRC_GAMMA_1_8, BABL_TRC_GAMMA_2_2, BABL_TRC_SRGB, + BABL_TRC_FORMULA_SRGB, BABL_TRC_LUT} BablTRCType; -- 2.30.2